package com.example.roleplay.service.impl;

import com.example.roleplay.config.RoleplayProperties;
import com.example.roleplay.domain.KnowledgeSnippet;
import com.example.roleplay.service.KnowledgeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 基于PostgreSQL向量数据库的知识库服务实现
 * 使用Spring AI和本地数据库进行RAG检索
 */
@Slf4j
@Service
@Primary
@RequiredArgsConstructor
public class PostgreSQLKnowledgeServiceImpl implements KnowledgeService {

    private final RoleplayProperties properties;
    private final VectorStore vectorStore;
    private final DocumentVectorizationService vectorizationService;
    
    // 本地备用知识片段存储
    private final Map<String, KnowledgeSnippet> fallbackSnippetStore = new ConcurrentHashMap<>();
    private final Map<String, List<KnowledgeSnippet>> categoryIndex = new ConcurrentHashMap<>();
    private long lastLoadTime = 0;

    @PostConstruct
    public void init() {
        // 加载本地备用知识库（苏格拉底相关）
        loadFallbackKnowledgeBase();
    }

    @Override
    public List<KnowledgeSnippet> searchSnippets(String query, int maxResults) {
        if (query == null || query.trim().isEmpty()) {
            return List.of();
        }

        try {
            log.info("使用PostgreSQL向量数据库搜索知识库: {}", query);
            
            // 首先尝试从向量数据库搜索
            List<KnowledgeSnippet> results = searchFromVectorDatabase(query, maxResults);
            
            if (!results.isEmpty()) {
                log.info("从PostgreSQL向量数据库检索到 {} 个相关片段", results.size());
                return results;
            }
            
            // 如果向量数据库没有结果，使用本地备用知识库
            log.debug("向量数据库无结果，使用本地备用知识库");
            return searchFromFallbackKnowledgeBase(query, maxResults);
            
        } catch (Exception e) {
            log.error("向量数据库搜索失败，使用本地备用知识库: {}", e.getMessage());
            return searchFromFallbackKnowledgeBase(query, maxResults);
        }
    }
    
    /**
     * 从PostgreSQL向量数据库搜索
     */
    private List<KnowledgeSnippet> searchFromVectorDatabase(String query, int maxResults) {
        try {
            if (vectorStore == null) {
                log.warn("向量存储未初始化，跳过向量数据库检索");
                return List.of();
            }
            
            log.debug("发送向量数据库检索请求: {}", query);
            
            // 调用向量存储进行相似性搜索
            List<Document> documents = vectorStore.similaritySearch(query);
            
            // 限制结果数量
            if (documents.size() > maxResults) {
                documents = documents.subList(0, maxResults);
            }
            
            log.debug("收到向量数据库响应: {} 个文档", documents.size());
            
            // 将Document转换为KnowledgeSnippet
            return convertDocumentsToSnippets(documents);
            
        } catch (Exception e) {
            log.error("PostgreSQL向量数据库搜索失败", e);
            throw e;
        }
    }
    
    /**
     * 将Document列表转换为KnowledgeSnippet列表
     */
    private List<KnowledgeSnippet> convertDocumentsToSnippets(List<Document> documents) {
        List<KnowledgeSnippet> snippets = new ArrayList<>();
        
        for (int i = 0; i < documents.size(); i++) {
            Document doc = documents.get(i);
            
            // 从元数据中获取文档信息
            String source = (String) doc.getMetadata().getOrDefault("source", "unknown");
            String category = (String) doc.getMetadata().getOrDefault("category", "文档知识库");
            
            // 生成更有意义的标题
            String title = generateMeaningfulTitle(doc.getText(), source, i + 1);
            
            KnowledgeSnippet snippet = KnowledgeSnippet.builder()
                .id("vector_doc_" + i)
                .title(title)
                .index(i + 1)
                .content(doc.getText())
                .category(category)
                .sourceFile(source)
                .weight(1.0 - (i * 0.05)) // 递减权重
                .build();
            
            snippets.add(snippet);
        }
        
        return snippets;
    }
    
    /**
     * 为文档片段生成有意义的标题
     */
    private String generateMeaningfulTitle(String content, String source, int index) {
        if (content == null || content.trim().isEmpty()) {
            return source + " - 片段 " + index;
        }
        
        // 取文档开头的前50个字符作为标题
        String title = content.trim();
        
        // 如果内容以标题标记开始，提取第一行作为标题
        if (title.startsWith("#")) {
            String[] lines = title.split("\n");
            if (lines.length > 0) {
                title = lines[0].replaceAll("^#+\\s*", "").trim();
                if (title.length() > 50) {
                    title = title.substring(0, 50) + "...";
                }
                return title;
            }
        }
        
        // 否则取前50个字符
        if (title.length() > 50) {
            title = title.substring(0, 50) + "...";
        }
        
        // 确保标题不包含换行符
        title = title.replaceAll("\n", " ").trim();
        
        return title.isEmpty() ? source + " - 片段 " + index : title;
    }
    
    /**
     * 从本地备用知识库搜索
     */
    private List<KnowledgeSnippet> searchFromFallbackKnowledgeBase(String query, int maxResults) {
        log.debug("使用本地备用知识库搜索: {}", query);
        String lowerQuery = query.toLowerCase();
        
        List<SnippetScore> scores = new ArrayList<>();
        
        for (KnowledgeSnippet snippet : fallbackSnippetStore.values()) {
            double score = calculateRelevanceScore(snippet, lowerQuery);
            log.debug("片段 {} 评分: {}, 阈值: {}", snippet.getTitle(), score, properties.getKnowledge().getSimilarityThreshold());
            if (score > properties.getKnowledge().getSimilarityThreshold()) {
                scores.add(new SnippetScore(snippet, score));
            }
        }
        
        List<KnowledgeSnippet> result = scores.stream()
                .sorted(Comparator.comparingDouble(SnippetScore::getScore).reversed())
                .limit(maxResults)
                .map(SnippetScore::getSnippet)
                .collect(Collectors.toList());
                
        log.info("本地备用知识库返回 {} 个结果（总共 {} 个片段）", result.size(), fallbackSnippetStore.size());
        return result;
    }
    
    /**
     * 计算相关度分数
     */
    private double calculateRelevanceScore(KnowledgeSnippet snippet, String query) {
        double score = 0.0;
        String lowerContent = snippet.getContent().toLowerCase();
        String lowerTitle = snippet.getTitle().toLowerCase();

        // 标题匹配权重更高
        if (lowerTitle.contains(query)) {
            score += 2.0;
        }

        // 内容匹配
        if (lowerContent.contains(query)) {
            score += 1.0;
        }

        // 计算关键词匹配度
        String[] queryWords = query.split("\\s+");
        for (String word : queryWords) {
            if (word.length() > 1) { // 忽略单字符词
                if (lowerTitle.contains(word)) {
                    score += 0.5;
                }
                if (lowerContent.contains(word)) {
                    score += 0.2;
                }
            }
        }

        return score * snippet.getWeight();
    }
    
    /**
     * 加载本地备用知识库
     */
    private void loadFallbackKnowledgeBase() {
        try {
            log.info("加载本地备用知识库...");
            fallbackSnippetStore.clear();
            categoryIndex.clear();

            // 加载苏格拉底相关知识片段（作为备用）
            loadSocratesKnowledge();

            lastLoadTime = System.currentTimeMillis();
            log.info("本地备用知识库加载完成，共 {} 个片段", fallbackSnippetStore.size());

        } catch (Exception e) {
            log.error("加载本地备用知识库失败", e);
        }
    }
    
    /**
     * 加载苏格拉底相关知识片段
     */
    private void loadSocratesKnowledge() {
        // 苏格拉底的核心思想和方法
        addFallbackSnippet("socrates_001", "苏格拉底的智慧", 1,
                "苏格拉底认为真正的智慧在于承认自己的无知。他的著名格言是：'我知道我什么都不知道。' 这种谦逊的态度成为了哲学探索的起点。",
                "哲学", "fallback");

        addFallbackSnippet("socrates_002", "苏格拉底方法", 1,
                "苏格拉底式提问法是通过一系列问题来引导对方思考，让学生自己发现真理，而不是直接告诉答案。这种方法被称为'助产术'。",
                "哲学", "fallback");

        addFallbackSnippet("socrates_003", "苏格拉底的哲学观", 1,
                "苏格拉底认为'未经审视的生活不值得过'。他强调自我反省和理性思考的重要性，认为哲学的目的是让人过上更好的生活。",
                "哲学", "fallback");

        addFallbackSnippet("socrates_004", "苏格拉底的教育理念", 1,
                "苏格拉底相信知识就是美德，认为如果人们真正理解什么是善，他们就会选择善行。无知是罪恶的根源。",
                "哲学", "fallback");

        addFallbackSnippet("socrates_005", "苏格拉底的对话方法", 1,
                "苏格拉底喜欢通过对话来探讨哲学问题。他会假装无知，通过提问来揭示对方观点中的矛盾，这种方法被称为'讽刺法'。",
                "哲学", "fallback");

        addFallbackSnippet("socrates_006", "苏格拉底的死亡", 1,
                "苏格拉底被雅典法庭以腐蚀青年和不敬神的罪名判处死刑。他拒绝逃跑，选择饮毒酒而死，体现了他对正义和法律的坚持。",
                "历史", "fallback");
    }
    
    /**
     * 添加备用知识片段
     */
    private void addFallbackSnippet(String id, String title, int index, String content, String category, String sourceFile) {
        KnowledgeSnippet snippet = KnowledgeSnippet.builder()
                .id(id)
                .title(title)
                .index(index)
                .content(content)
                .category(category)
                .sourceFile(sourceFile)
                .weight(1.0)
                .build();

        fallbackSnippetStore.put(id, snippet);
        categoryIndex.computeIfAbsent(category, k -> new ArrayList<>()).add(snippet);
    }

    @Override
    public List<KnowledgeSnippet> getAllSnippets() {
        // 返回本地备用知识片段（向量数据库的内容无法直接枚举）
        return new ArrayList<>(fallbackSnippetStore.values());
    }

    @Override
    public List<KnowledgeSnippet> getSnippetsByCategory(String category) {
        return categoryIndex.getOrDefault(category, List.of());
    }
    
    /**
     * 片段评分辅助类
     */
    private static class SnippetScore {
        private final KnowledgeSnippet snippet;
        private final double score;

        public SnippetScore(KnowledgeSnippet snippet, double score) {
            this.snippet = snippet;
            this.score = score;
        }

        public KnowledgeSnippet getSnippet() { return snippet; }
        public double getScore() { return score; }
    }
}